home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Mail / pine3.92 / pine / signals.c < prev    next >
C/C++ Source or Header  |  1996-03-14  |  26KB  |  991 lines

  1. #if !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: signals.c,v 4.93 1996/03/15 07:13:42 hubert Exp $";
  3. #endif
  4. /*----------------------------------------------------------------------
  5.  
  6.             T H E    P I N E    M A I L   S Y S T E M
  7.  
  8.    Laurence Lundblade and Mike Seibel
  9.    Networks and Distributed Computing
  10.    Computing and Communications
  11.    University of Washington
  12.    Administration Builiding, AG-44
  13.    Seattle, Washington, 98195, USA
  14.    Internet: lgl@CAC.Washington.EDU
  15.              mikes@CAC.Washington.EDU
  16.  
  17.    Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  18.  
  19.  
  20.    Pine and Pico are registered trademarks of the University of Washington.
  21.    No commercial use of these trademarks may be made without prior written
  22.    permission of the University of Washington.
  23.  
  24.    Pine, Pico, and Pilot software and its included text are Copyright
  25.    1989-1996 by the University of Washington.
  26.  
  27.    The full text of our legal notices is contained in the file called
  28.    CPYRIGHT, included with this distribution.
  29.  
  30.  
  31.    Pine is in part based on The Elm Mail System:
  32.     ***********************************************************************
  33.     *  The Elm Mail System  -  Revision: 2.13                             *
  34.     *                                                                     *
  35.     *             Copyright (c) 1986, 1987 Dave Taylor              *
  36.     *             Copyright (c) 1988, 1989 USENET Community Trust   *
  37.     ***********************************************************************
  38.  
  39.  
  40.   ----------------------------------------------------------------------*/
  41.  
  42. /*======================================================================
  43.      signals.c
  44.      Different signal handlers for different signals
  45.        - Catches all the abort signals, cleans up tty modes and then coredumps
  46.        - Not much to do for SIGHUP
  47.        - Not much to do for SIGTERM
  48.        - turn SIGWINCH into a KEY_RESIZE command
  49.        - No signals for ^Z/suspend, but do it here anyway
  50.        - Also set up the signal handlers, and hold signals for
  51.          critical imap sections of code.
  52.  
  53.  ====*/
  54.  
  55. #include "headers.h"
  56.  
  57. /*
  58.  * call used by TERM and HUP handlers to quickly close streams
  59.  */
  60. void  fast_clean_up PROTO(());
  61. void  suspend_notice PROTO((char *));
  62. void  suspend_warning PROTO(());
  63.  
  64. #if defined(DOS) || defined(OS2)
  65. #define    SIG_PROTO(args) args
  66. #else
  67. #define    SIG_PROTO(args) ()
  68. #endif
  69.  
  70.  
  71.               /* SigType is defined in os.h and is either int or void */
  72. static    SigType    auger_in_signal SIG_PROTO((int));
  73. static    SigType    winch_signal SIG_PROTO((int));
  74. static    SigType    usr2_signal SIG_PROTO((int));
  75. static    SigType    alarm_signal SIG_PROTO((int));
  76. static    SigType    intr_signal SIG_PROTO((int));
  77.  
  78.  
  79. /*----------------------------------------------------------------------
  80.     Install handlers for all the signals we care to catch
  81.   ----------------------------------------------------------------------*/
  82. void
  83. init_signals()
  84. {
  85.     dprint(9, (debugfile, "init_signals()\n"));
  86. #ifdef    _WINDOWS
  87.     /* Only one signal works. */
  88.     signal(SIGALRM, (void *)alarm_signal);
  89.     signal(SIGHUP, (void *)hup_signal);
  90. #else
  91. #ifdef OS2
  92.     dont_interrupt();
  93.     signal(SIGALRM, (void *)alarm_signal);
  94.     signal(SIGHUP, (void *)hup_signal);
  95. #else
  96. #if defined(DOS)
  97.     dont_interrupt();
  98. #else
  99. #ifdef DEBUG
  100. #define    CUSHION_SIG    (debug < 7)
  101. #else
  102. #define    CUSHION_SIG    (1)
  103. #endif
  104.  
  105.     if(CUSHION_SIG){
  106.     signal(SIGILL,  auger_in_signal); 
  107.     signal(SIGTRAP, auger_in_signal);
  108.     signal(SIGEMT,  auger_in_signal);
  109.     signal(SIGBUS,  auger_in_signal);
  110.     signal(SIGSEGV, auger_in_signal);
  111.     signal(SIGSYS,  auger_in_signal);
  112.     signal(SIGQUIT, auger_in_signal);
  113.     /* Don't catch SIGFPE cause it's rare and we use it in a hack below*/
  114.     }
  115.     
  116.     init_sigwinch();
  117.     
  118.     signal(SIGHUP, hup_signal);
  119.     signal(SIGTERM, term_signal);
  120.     
  121.     /*
  122.      * Set up SIGUSR2 to catch signal from other software using the 
  123.      * c-client to tell us that other access to the folder is being 
  124.      * attempted.  THIS IS A TEST: if it turns out that simply
  125.      * going R/O when another pine is started or the same folder is opened,
  126.      * then we may want to install a smarter handler that uses idle time
  127.      * or even prompts the user to see if it's ok to give up R/O access...
  128.      */
  129.     signal(SIGUSR2, usr2_signal);
  130.     
  131. #ifdef SA_RESTART
  132.     {
  133.     struct sigaction sa;
  134.  
  135.     sa.sa_handler = alarm_signal;
  136.     memset(&sa.sa_mask, 0, sizeof(sa.sa_mask));
  137.     sa.sa_flags = SA_RESTART;
  138.     sigaction(SIGALRM, &sa, NULL);
  139.     }
  140. #else
  141.     signal(SIGALRM, alarm_signal);
  142. #endif
  143.  
  144.     signal(SIGPIPE, SIG_IGN);
  145.     signal(SIGINT, SIG_IGN);
  146.  
  147. #ifdef SIGTSTP
  148.     /* Some unexplained behaviour on Ultrix 4.2 (Hardy) seems to be
  149.        resulting in Pine getting sent a SIGTSTP. Ignore it here.
  150.        probably better to ignore it than let it happen in any case
  151.      */
  152.     signal(SIGTSTP, SIG_IGN); 
  153. #endif /* SIGTSTP */
  154. #endif    /* !DOS */
  155. #endif    /* !OS2 */
  156. #endif    /* !_WINDOWS */
  157. }
  158.  
  159.  
  160.  
  161. /*----------------------------------------------------------------------
  162.     Return all signal handling back to normal
  163.   ----------------------------------------------------------------------*/
  164. void
  165. end_signals(blockem)
  166.     int blockem;
  167. {
  168. #ifdef    _WINDOWS
  169.     signal(SIGALRM, blockem ? SIG_IGN : SIG_DFL);
  170.     signal(SIGHUP,  blockem ? SIG_IGN : SIG_DFL);
  171. #else
  172. #ifdef    OS2
  173.     interrupt_ok();
  174.     signal(SIGALRM, blockem ? SIG_IGN : SIG_DFL);
  175.     signal(SIGHUP,  blockem ? SIG_IGN : SIG_DFL);
  176. #else
  177. #ifdef    DOS
  178.     interrupt_ok();
  179. #else
  180. #ifndef    SIG_ERR
  181. #define    SIG_ERR    (SigType (*)())-1
  182. #endif
  183.  
  184.     dprint(5, (debugfile, "end_signals(%d)\n", blockem));
  185.     if(signal(SIGILL,  blockem ? SIG_IGN : SIG_DFL) == SIG_ERR){
  186.         fprintf(stderr, "Error resetting signals: %s\n",
  187.                 error_description(errno));
  188.         exit(-1);
  189.     }
  190.  
  191.     signal(SIGTRAP, blockem ? SIG_IGN : SIG_DFL);
  192.     signal(SIGEMT,  blockem ? SIG_IGN : SIG_DFL);
  193.     signal(SIGBUS,  blockem ? SIG_IGN : SIG_DFL);
  194.     signal(SIGSEGV, blockem ? SIG_IGN : SIG_DFL);
  195.     signal(SIGSYS,  blockem ? SIG_IGN : SIG_DFL);
  196. #ifdef RESIZING
  197.     signal(SIGWINCH, blockem ? SIG_IGN : SIG_DFL);
  198. #endif
  199.     signal(SIGQUIT, blockem ? SIG_IGN : SIG_DFL);
  200. #ifdef SIGTSTP
  201.     signal(SIGTSTP, blockem ? SIG_IGN : SIG_DFL);
  202. #endif /* SIGTSTP */
  203.     signal(SIGHUP,  blockem ? SIG_IGN : SIG_DFL);
  204.     signal(SIGALRM, blockem ? SIG_IGN : SIG_DFL);
  205.     signal(SIGTERM, blockem ? SIG_IGN : SIG_DFL);
  206.     signal(SIGINT,  blockem ? SIG_IGN : SIG_DFL);
  207. #endif    /* !DOS */
  208. #endif    /* !OS2 */
  209. #endif    /* !_WINDOWS */
  210. }
  211.  
  212.  
  213. /*----------------------------------------------------------------------
  214.      Handle signals caused by aborts -- SIGSEGV, SIGILL, etc
  215.  
  216. Call panic which cleans up tty modes and then core dumps
  217.   ----------------------------------------------------------------------*/
  218. static SigType
  219. auger_in_signal SIG_PROTO ((int sig))
  220. {
  221.     end_signals(1);            /* don't catch any more signals */
  222.     dprint(5, (debugfile, "auger_in_signal()\n"));
  223.     panic("Received abort signal");    /* clean up and get out */
  224.     exit(-1);                /* in case panic doesn't kill us */
  225. }
  226.  
  227.  
  228. /*----------------------------------------------------------------------
  229.       handle hang up signal -- SIGHUP
  230.  
  231. Not much to do. Rely on periodic mail file check pointing.
  232.   ----------------------------------------------------------------------*/
  233. SigType
  234. hup_signal()
  235. {
  236. #if    !defined(DOS) || defined(_WINDOWS)
  237.     end_signals(1);            /* don't catch any more signals */
  238.     dprint(1, (debugfile, "\n\n** Received SIGHUP **\n\n\n\n"));
  239.     fast_clean_up();
  240.     printf("\n\nPine finished. Received hang up signal\n\n");
  241. #endif    /* !DOS */
  242.     exit(0);
  243. }
  244.  
  245.  
  246. /*----------------------------------------------------------------------
  247.       handle terminate signal -- SIGTERM
  248.  
  249. Not much to do. Rely on periodic mail file check pointing.
  250.   ----------------------------------------------------------------------*/
  251. SigType
  252. term_signal()
  253. {
  254. #if !defined(DOS) && !defined(OS2)
  255.     end_signals(1);            /* don't catch any more signals */
  256.     dprint(1, (debugfile, "\n\n** Received SIGTERM **\n\n\n\n"));
  257.     fast_clean_up();
  258.     printf("\n\nPine finished. Received terminate signal\n\n");
  259. #endif    /* !DOS */
  260.     exit(0);
  261. }
  262.  
  263.  
  264. /*----------------------------------------------------------------------
  265.      Handle cleaning up mail streams and tty modes...
  266. Not much to do. Rely on periodic mail file check pointing.  Don't try
  267. cleaning up screen or flushing output since stdout is likely already
  268. gone.  To be safe, though, we'll at least restore the original tty mode.
  269.   ----------------------------------------------------------------------*/
  270. void
  271. fast_clean_up()
  272. {
  273. #if !defined(DOS) && !defined(OS2)
  274.     if(ps_global->inbox_stream != NULL && !ps_global->inbox_stream->lock){
  275.         if(ps_global->inbox_stream == ps_global->mail_stream)
  276.           ps_global->mail_stream = NULL; 
  277.         mail_close(ps_global->inbox_stream);
  278.     }
  279.  
  280.     if(ps_global->mail_stream != NULL &&
  281.        ps_global->mail_stream != ps_global->inbox_stream &&
  282.        !ps_global->mail_stream->lock)
  283.       mail_close(ps_global->mail_stream);
  284.  
  285.     Raw(0);
  286.  
  287. #endif    /* !DOS */
  288. #if    defined(DEBUG) && (!defined(DOS) || defined(_WINDOWS))
  289.     if(debugfile)
  290.       fclose(debugfile);
  291. #endif 
  292. }
  293.  
  294.  
  295. #if !defined(DOS) && !defined(OS2)
  296. /*----------------------------------------------------------------------
  297.       handle hang up signal -- SIGUSR2
  298.  
  299. Not much to do. Rely on periodic mail file check pointing.
  300.   ----------------------------------------------------------------------*/
  301. static SigType
  302. usr2_signal SIG_PROTO((int sig))
  303. {
  304.     char c;
  305.     dprint(1, (debugfile, "\n\n** Received SIGUSR2 **\n\n\n\n"));
  306.  
  307.     if(ps_global->inbox_stream
  308.        && !ps_global->inbox_stream->lock
  309.        && !ps_global->inbox_stream->rdonly
  310.        && (c = *ps_global->inbox_stream->mailbox) != '{' && c != '*'){
  311.     mail_check(ps_global->inbox_stream);    /* write latest state   */
  312.     ps_global->inbox_stream->rdonly = 1;    /* and become read-only */
  313.     mail_ping(ps_global->inbox_stream);
  314.     q_status_message(SM_ASYNC, 3, 7,
  315.            "Another Pine is accessing Inbox.  Session now Read-Only.");
  316.     dprint(1, (debugfile, "** INBOX went read-only **\n\n"));
  317.     }
  318.  
  319.     if(ps_global->mail_stream
  320.        && !ps_global->mail_stream->lock
  321.        && !ps_global->mail_stream->rdonly
  322.        && (c = *ps_global->mail_stream->mailbox) != '{' && c != '*'){
  323.     mail_check(ps_global->mail_stream);    /* write latest state   */
  324.     ps_global->mail_stream->rdonly = 1;    /* and become read-only */
  325.     mail_ping(ps_global->mail_stream);
  326.     q_status_message(SM_ASYNC, 3, 7,
  327.           "Another Pine is accessing folder.  Session now Read-Only.");
  328.     dprint(1, (debugfile, "** secondary folder went read-only **\n\n"));
  329.     }
  330. }
  331. #endif
  332.  
  333.  
  334.  
  335. /*----------------------------------------------------------------------
  336.    Install signal handler to deal with window resize signal -- SIGWINCH
  337.   
  338.   ----------------------------------------------------------------------*/
  339. void
  340. init_sigwinch ()
  341. {
  342. #ifdef RESIZING
  343.     signal(SIGWINCH, winch_signal);
  344. #endif
  345. }
  346.  
  347.  
  348. #ifdef RESIZING
  349. /*----------------------------------------------------------------------
  350.    Handle window resize signal -- SIGWINCH
  351.   
  352.    The planned strategy is just force a redraw command. This is similar
  353.   to new mail handling which forces a noop command. The signals are
  354.   help until pine reads input. Then a KEY_RESIZE is forced into the command
  355.   stream .
  356.    Note that ready_for_winch is only non-zero inside the read_char function,
  357.   so the longjmp only ever happens there, and it is really just a jump
  358.   from lower down in the function up to the top of that function.  Its
  359.   purpose is to return a KEY_RESIZE from read_char when interrupted
  360.   out of the select lower down in read_char.
  361.   ----------------------------------------------------------------------*/
  362. extern jmp_buf  winch_state;
  363. extern int      ready_for_winch, winch_occured;
  364.  
  365. SigType
  366. static winch_signal SIG_PROTO((int sig))
  367. {
  368.     dprint(9,(debugfile, "SIGWINCH ready_for_winch: %d winch_occured:%d\n",
  369.                ready_for_winch, winch_occured));
  370.     clear_cursor_pos();
  371.     init_sigwinch();
  372.     if(ready_for_winch)
  373.       longjmp(winch_state, 1);
  374.     else
  375.       winch_occured = 1;
  376. }
  377. #endif
  378.  
  379.  
  380. #ifdef    SIGCHLD
  381. /*----------------------------------------------------------------------
  382.    Handle child status change -- SIGCHLD
  383.   
  384.    The strategy here is to install the handler when we spawn a child, and
  385.    to let the system tell us when the child's state has changed.  In the
  386.    mean time, we can do whatever.  Typically, "whatever" is spinning in a
  387.    loop alternating between sleep and new_mail calls intended to keep the
  388.    IMAP stream alive.
  389.  
  390.   ----------------------------------------------------------------------*/
  391. extern short    child_signalled, child_jump;
  392. extern jmp_buf  child_state;
  393.  
  394. SigType
  395. child_signal()
  396. {
  397.     dprint(9,(debugfile, "SIGCHLD raised\n"));
  398.     child_signalled = 1;
  399.     if(child_jump)
  400.       longjmp(child_state, 1);
  401. }
  402. #endif
  403.  
  404.  
  405. #define MAX_BM          80  /* max length of busy message */
  406. static unsigned       alarm_increment;
  407. static int            dotcount;
  408. static char           busy_message[MAX_BM + 1];
  409. static int            busy_alarm_outstanding;
  410. static int            busy_len;
  411. static int            final_message;
  412. static int            callcount;
  413. static percent_done_t percent_done_ptr;
  414. static char *display_chars[] = {
  415.     "<\\> ",
  416.     "<|> ",
  417.     "</> ",
  418.     "<-> ",
  419.     "    ",
  420.     "<-> "
  421. };
  422. #define DISPLAY_CHARS_ROWS 6
  423. #define DISPLAY_CHARS_COLS 4
  424.  
  425. /*
  426.  * Turn on a busy alarm.
  427.  *
  428.  *    seconds -- alarm fires every seconds seconds
  429.  *        msg -- the busy message to print in status line
  430.  *    pc_func -- if non-null, call this function to get the percent done,
  431.  *           (an integer between 0 and 100).  If null, append dots.
  432.  *   init_msg -- if non-zero, force out an immediate status message instead
  433.  *                 of waiting for first alarm (except see comments in code)
  434.  *
  435.  *   Returns:  0 If busy alarm was already set up before we got here
  436.  *             1 If busy alarm was not already set up.
  437.  */
  438. int
  439. busy_alarm(seconds, msg, pc_func, init_msg)
  440.     unsigned       seconds;
  441.     char          *msg;
  442.     percent_done_t pc_func;
  443.     int            init_msg;
  444. {
  445.     int retval = 1;
  446.  
  447.     dprint(9,(debugfile, "busy_alarm(%d, %s, %p, %d)\n",
  448.     seconds, msg ? msg : "Busy", pc_func, init_msg));
  449.  
  450.     /*
  451.      * If we're already busy'ing, and we don't have something special,
  452.      * just leave it alone.
  453.      */
  454.     if(busy_alarm_outstanding){
  455.     retval = 0;
  456.     if(!msg && !pc_func)
  457.       return(retval);
  458.     }
  459.  
  460.     if(seconds){
  461.     busy_alarm_outstanding = 1;
  462.     alarm_increment = seconds;
  463.     dotcount = 0;
  464.     percent_done_ptr = pc_func;
  465.     callcount = 0;
  466.  
  467.     if(msg){
  468.         strncpy(busy_message, msg, MAX_BM);
  469.         final_message = 1;
  470.     }
  471.     else{
  472.         strcpy(busy_message, "Busy");
  473.         final_message = 0;
  474.     }
  475.  
  476.     busy_message[MAX_BM] = '\0';
  477.     busy_len = strlen(busy_message);
  478.  
  479.     if(init_msg){
  480.         char progress[MAX_SCREEN_COLS+1];
  481.         int space_left, slots_used;
  482.  
  483.         final_message = 1;
  484.         space_left = (ps_global->ttyo ? ps_global->ttyo->screen_cols
  485.                       : 80) -
  486.                       busy_len - 2;  /* 2 is for [] */
  487.         slots_used = max(0, min(space_left-3, 10));
  488.  
  489.         if(percent_done_ptr && slots_used >= 4){
  490.         sprintf(progress, "%s |%*s|", busy_message, slots_used, "");
  491.         q_status_message(SM_ORDER, 0, 1, progress);
  492.         }
  493.         else{
  494.         dotcount++;
  495.         sprintf(progress, "%s%*s", busy_message,
  496.             DISPLAY_CHARS_COLS + 1, "");
  497.         q_status_message(SM_ORDER, 0, 1, progress);
  498.         }
  499.  
  500.         /*
  501.          * We use display_message so that the initial message will
  502.          * be forced out only if there is not a previous message
  503.          * currently being displayed that hasn't been displayed for
  504.          * its min display time yet.  In that case, we don't want
  505.          * to force out the initial message.
  506.          */
  507.         display_message('x');
  508.     }
  509.     
  510. #ifdef _WINDOWS
  511.     mswin_setcursor (MSWIN_CURSOR_BUSY);
  512. #endif
  513.     fflush(stdout);
  514.     }
  515.  
  516.     /* set alarm */
  517.     (void)alarm(seconds);
  518.     return(retval);
  519. }
  520.  
  521.  
  522. /*
  523.  * If final_message was set when busy_alarm was called:
  524.  *   and message_pri = -1 -- no final message queued
  525.  *                 else final message queued with min equal to message_pri
  526.  */
  527. void
  528. cancel_busy_alarm(message_pri)
  529.     int message_pri;
  530. {
  531.     dprint(9,(debugfile, "cancel_busy_alarm(%d)\n", message_pri));
  532.  
  533.     (void)alarm(0);
  534.  
  535.     if(busy_alarm_outstanding){
  536.     int space_left, slots_used;
  537.  
  538.     busy_alarm_outstanding = 0;
  539.  
  540.     if(final_message && message_pri >= 0){
  541.         char progress[MAX_SCREEN_COLS+1];
  542.  
  543.         space_left = (ps_global->ttyo ? ps_global->ttyo->screen_cols : 80) -
  544.         busy_len - 2;  /* 2 is for [] */
  545.         slots_used = max(0, min(space_left-3, 10));
  546.  
  547.         if(percent_done_ptr && slots_used >= 4){
  548.         int left, right;
  549.  
  550.         right = (slots_used - 4)/2;
  551.         left  = slots_used - 4 - right;
  552.         sprintf(progress, "%s |%*s100%%%*s|",
  553.             busy_message, left, "", right, "");
  554.         q_status_message(SM_ORDER,
  555.             message_pri>=2 ? max(message_pri,3) : 0,
  556.             message_pri+2, progress);
  557.         }
  558.         else{
  559.         sprintf(progress, "%s%*sDONE", busy_message,
  560.             DISPLAY_CHARS_COLS - 4 + 1, "");
  561.         q_status_message(SM_ORDER,
  562.             message_pri>=2 ? max(message_pri,3) : 0,
  563.             message_pri+2, progress);
  564.         }
  565.     }
  566.     else
  567.       mark_status_dirty();
  568.     }
  569. }
  570.  
  571.  
  572. /*
  573.  * suspend_busy_alarm - continue previously installed busy_alarm.
  574.  */
  575. void
  576. suspend_busy_alarm()
  577. {
  578.     dprint(9,(debugfile, "suspend_busy_alarm\n"));
  579.  
  580.     if(busy_alarm_outstanding)
  581.       alarm(0);
  582. }
  583.  
  584.  
  585. /*
  586.  * resume_busy_alarm - continue previously installed busy_alarm.
  587.  */
  588. void
  589. resume_busy_alarm()
  590. {
  591.     dprint(9,(debugfile, "resume_busy_alarm\n"));
  592.  
  593.     if(busy_alarm_outstanding)
  594.       (void)alarm(alarm_increment);
  595. }
  596.  
  597.  
  598. static SigType
  599. alarm_signal SIG_PROTO((int sig))
  600. {
  601.     int space_left, slots_used;
  602.     char dbuf[MAX_SCREEN_COLS+1];
  603.  
  604.     dprint(9,(debugfile, "alarm_signal()\n"));
  605.  
  606.     space_left = (ps_global->ttyo ? ps_global->ttyo->screen_cols : 80) -
  607.     busy_len - 2;  /* 2 is for [] */
  608.     slots_used = max(0, min(space_left-3, 10));
  609.  
  610.     if(percent_done_ptr && slots_used >= 4){
  611.     int completed, pd;
  612.     char *s;
  613.  
  614.     pd = (*percent_done_ptr)();
  615.     pd = min(max(0, pd), 100);
  616.  
  617.     completed = (pd * slots_used) / 100;
  618.     sprintf(dbuf, "%s |%s%s%*s|", busy_message,
  619.         completed > 1 ? repeat_char(completed-1, pd==100 ? ' ' : '-') : "",
  620.         (completed > 0 && pd != 100) ? ">" : "",
  621.         slots_used - completed, "");
  622.  
  623.     if(slots_used == 10){
  624.         s = dbuf + strlen(dbuf) - 8;
  625.         if(pd < 10){
  626.         s++; s++;
  627.         *s++ = '0' + pd;
  628.         }
  629.         else if(pd < 100){
  630.         s++;
  631.         *s++ = '0' + pd / 10;
  632.         *s++ = '0' + pd % 10;
  633.         }
  634.         else{
  635.         *s++ = '1';
  636.         *s++ = '0';
  637.         *s++ = '0';
  638.         }
  639.  
  640.         *s   = '%';
  641.     }
  642.     }
  643.     else{
  644.     char b[DISPLAY_CHARS_COLS + 2];
  645.     int md = DISPLAY_CHARS_ROWS - 2;
  646.     int ind;
  647.  
  648.     ind = (dotcount == 0) ? md :
  649.            (dotcount == 1) ? md + 1 : ((dotcount-2) % md);
  650.  
  651.     if(space_left >= DISPLAY_CHARS_COLS + 1){
  652.         b[0] = SPACE;
  653.         strcpy(b+1, display_chars[ind]);
  654.     }
  655.     else if(space_left >= 2){
  656.         b[0] = '.';
  657.         b[1] = '.';
  658.         b[2] = '.';
  659.         b[space_left] = '\0';
  660.     }
  661.     else
  662.       b[0] = '\0';
  663.  
  664.     sprintf(dbuf, "%s%s", busy_message, b);
  665.     }
  666.  
  667.     status_message_write(dbuf, 1);
  668.     dotcount++;
  669.     fflush(stdout);
  670.  
  671. #ifdef SA_RESTART
  672.     {
  673.     struct sigaction sa;
  674.  
  675.     sa.sa_handler = alarm_signal;
  676.     memset(&sa.sa_mask, 0, sizeof(sa.sa_mask));
  677.     sa.sa_flags = SA_RESTART;
  678.     sigaction(SIGALRM, &sa, NULL);
  679.     }
  680. #else
  681. #if    !defined(DOS) || defined(_WINDOWS)
  682.     signal(SIGALRM, alarm_signal);
  683. #endif
  684. #endif
  685.     (void)alarm(alarm_increment);
  686. }
  687.  
  688. #ifdef    DOS
  689. /*
  690.  * For systems that don't have an alarm() call.
  691.  */
  692. void
  693. fake_alarm_blip()
  694. {
  695.     static time_t   last_alarm = -1;
  696.     time_t        now;
  697.  
  698.     if(busy_alarm_outstanding &&
  699.        ++callcount % 5 == 0 &&
  700.        (long)((now=time((time_t *)0)) - last_alarm) >= (long)alarm_increment){
  701.     last_alarm = now;
  702.     /* manually execute code that an alarm would cause to execute */
  703.     alarm_signal(1);
  704.     }
  705. }
  706. #endif
  707.  
  708.  
  709. /*
  710.  * Command interrupt support.
  711.  */
  712.  
  713. static SigType
  714. intr_signal SIG_PROTO((int sig))
  715. {
  716.     ps_global->intr_pending = 1;
  717. }
  718.  
  719.  
  720. void
  721. intr_allow()
  722. {
  723.     if(signal(SIGINT, intr_signal) == intr_signal)
  724.       return;                /* already installed */
  725.  
  726.     intr_proc(1);            /* turn on interrupt char */
  727. }
  728.  
  729.  
  730. void
  731. intr_disallow()
  732. {
  733.     if(signal(SIGINT, SIG_IGN) == SIG_IGN)    /* already off! */
  734.       return;
  735.  
  736. #ifdef POSIX_SIGNALS
  737.     sigrelse(SIGINT);            /* unblock signal after longjmp */
  738. #endif
  739.     ps_global->intr_pending = 0;
  740.     intr_proc(0);            /* turn off interrupt char */
  741. }
  742.  
  743.  
  744. void
  745. intr_handling_on()
  746. {
  747.     if(signal(SIGINT, intr_signal) == intr_signal)
  748.       return;                /* already installed */
  749.  
  750.     intr_proc(1);
  751.     draw_cancel_keymenu();
  752. }
  753.  
  754.  
  755. void
  756. intr_handling_off()
  757. {
  758.     if(signal(SIGINT, SIG_IGN) == SIG_IGN)    /* already off! */
  759.       return;
  760.  
  761.     ps_global->intr_pending = 0;
  762.     intr_proc(0);
  763.     blank_keymenu(ps_global->ttyo->screen_rows - 2, 0);
  764.     ps_global->mangled_footer = 1;
  765. }
  766.  
  767.  
  768. /*----------------------------------------------------------------------
  769.      Suspend Pine. Reset tty and suspend. Suspend is finished when this returns
  770.  
  771.    Args:  The pine structure
  772.  
  773.  Result:  Execution suspended for a while. Screen will need redrawing 
  774.           after this is done.
  775.  
  776.  Instead of the usual handling of ^Z by catching a signal, we actually read
  777. the ^Z and then clean up the tty driver, then kill ourself to stop, and 
  778. pick up where we left off when execution resumes.
  779.   ----------------------------------------------------------------------*/
  780. int
  781. do_suspend(pine) 
  782.     struct pine *pine;
  783. {
  784.     time_t now;
  785.     int   result, isremote, retval;
  786.     int   orig_cols, orig_rows;
  787. #ifdef    DOS
  788.     static char *shell = NULL;
  789. #define    STD_SHELL    "COMMAND.COM"
  790. #else
  791. #ifdef    OS2
  792.     static char *shell = NULL;
  793. #define    STD_SHELL    "CMD.EXE"
  794. #else
  795.     char *shell;
  796. #endif
  797. #endif
  798.  
  799.     if(!have_job_control()){
  800.     bogus_command(ctrl('Z'), F_ON(F_USE_FK, pine) ? "F1" : "?");
  801.     return(NO_OP_COMMAND);
  802.     }
  803.  
  804.     if(F_OFF(F_CAN_SUSPEND, pine)){
  805.     q_status_message(SM_ORDER | SM_DING, 3, 3,
  806.              "Pine suspension not enabled - see help text");
  807.     return(NO_OP_COMMAND);
  808.     }
  809.  
  810. #ifdef    _WINDOWS
  811.     /* suspend what? */
  812. #else
  813.  
  814.     isremote = (ps_global->mail_stream && ps_global->mail_stream->mailbox
  815.         && (*ps_global->mail_stream->mailbox == '{'
  816.             || (*ps_global->mail_stream->mailbox == '*'
  817.             && *(ps_global->mail_stream->mailbox + 1) == '{')));
  818.  
  819.     now = time((time_t *)0);
  820.     dprint(1, (debugfile, "\n\n --- %s - SUSPEND ----  %s",
  821.            isremote ? "REMOTE" : "LOCAL", ctime(&now)));
  822.     EndInverse();
  823.     end_keyboard(F_ON(F_USE_FK,pine));
  824.     end_tty_driver(pine);
  825.     end_screen(NULL);
  826. #if defined(DOS) || defined(OS2)
  827. #ifdef OS2
  828.     interrupt_ok();
  829. #endif
  830.     suspend_notice("exit");
  831.     if (!shell){
  832.     char *p;
  833.  
  834.     if (!((shell = getenv("SHELL")) || (shell = getenv("COMSPEC"))))
  835.       shell = STD_SHELL;
  836.  
  837.     shell = cpystr(shell);            /* copy in free storage */
  838.     for(p = shell; p = strchr(p, '/'); p++)
  839.       *p = '\\';
  840.     }
  841.  
  842.     result = system(shell);
  843. #else
  844.     if(F_ON(F_SUSPEND_SPAWNS, ps_global)){
  845.     PIPE_S *syspipe;
  846.  
  847.     if(syspipe = open_system_pipe(NULL, NULL, NULL, PIPE_USER|PIPE_RESET)){
  848.         suspend_notice("exit");
  849. #ifndef    SIGCHLD
  850.         if(isremote)
  851.           suspend_warning();
  852. #endif
  853.         (void) close_system_pipe(&syspipe);
  854.     }
  855.     }
  856.     else{
  857.     suspend_notice("fg");
  858.  
  859.     if(isremote)
  860.       suspend_warning();
  861.  
  862.     stop_process();
  863.     }
  864. #endif    /* DOS */
  865.  
  866.     now = time((time_t *)0);
  867.     dprint(1, (debugfile, "\n\n ---- RETURN FROM SUSPEND ----  %s",
  868.                ctime(&now)));
  869.     init_screen();
  870.     init_tty_driver(pine);
  871.     init_keyboard(F_ON(F_USE_FK,pine));
  872.  
  873. #ifdef OS2
  874.     dont_interrupt();
  875. #endif
  876.     orig_cols = pine->ttyo->screen_cols;
  877.     orig_rows = pine->ttyo->screen_rows;
  878.     fix_windsize(pine);
  879. #if defined(DOS) || defined(OS2)
  880.     if(orig_cols != pine->ttyo->screen_cols ||
  881.        orig_rows != pine->ttyo->screen_rows)
  882.     retval = KEY_RESIZE;
  883.     else
  884. #endif
  885.     retval = ctrl('L');;
  886.  
  887. #if    defined(DOS) || defined(OS2)
  888.     if(result == -1)
  889.       q_status_message1(SM_ORDER | SM_DING, 3, 4,
  890.             "Error loading \"%s\"", shell);
  891. #endif
  892.  
  893.     if(isremote && (char *)mail_ping(ps_global->mail_stream) == NULL)
  894.       q_status_message(SM_ORDER | SM_DING, 4, 9,
  895.                "Suspended for too long, IMAP connection broken");
  896.  
  897.     return(retval);
  898. #endif    /* !_WINDOWS */
  899. }
  900.  
  901.  
  902.  
  903. /*----------------------------------------------------------------------
  904.  ----*/
  905. void
  906. suspend_notice(s)
  907.     char *s;
  908. {
  909.     printf("\nPine suspended. Give the \"%s\" command to come back.\n", s);
  910.     fflush(stdout);
  911. }
  912.  
  913.  
  914.  
  915. /*----------------------------------------------------------------------
  916.  ----*/
  917. void
  918. suspend_warning()
  919. {
  920.     puts("Warning: Your IMAP connection will be closed if Pine");
  921.     puts("is suspended for more than 30 minutes\n");
  922.     fflush(stdout);
  923. }
  924.  
  925.  
  926.  
  927. /*----------------------------------------------------------------------
  928.  ----*/
  929. void
  930. fix_windsize(pine)
  931.     struct pine *pine;
  932. {
  933.     mark_keymenu_dirty();
  934.     mark_status_dirty();
  935.     mark_titlebar_dirty();
  936.     clear_cursor_pos();
  937. #ifdef RESIZING
  938.     get_windsize(pine->ttyo);
  939. #endif /* RESIZING */
  940. }
  941.  
  942.  
  943. #if defined(DOS) || defined(OS2)
  944. SigType (*hold_int)(int), (*hold_term)(int), (*hold_quit)(int);
  945. #else
  946. SigType (*hold_hup)(), (*hold_int)(), (*hold_term)(), (*hold_usr2)(),
  947.     (*hold_quit)();
  948. #endif
  949.  
  950. /*----------------------------------------------------------------------
  951.      Ignore signals when imap is running through critical code
  952.  
  953.  Args: stream -- The stream on which critical operation is proceeding
  954.  ----*/
  955.  
  956. void 
  957. mm_critical(stream)
  958.      MAILSTREAM *stream;
  959. {
  960.     stream = stream; /* For compiler complaints that this isn't used */
  961. #if !defined(DOS) && !defined(OS2)
  962.     hold_hup  = signal(SIGHUP, SIG_IGN);
  963.     hold_usr2 = signal(SIGUSR2, SIG_IGN);
  964. #endif
  965.     hold_int  = signal(SIGINT, SIG_IGN);
  966.     hold_term = signal(SIGTERM, SIG_IGN);
  967.     dprint(9, (debugfile, "Done with IMAP critical on %s\n",
  968.               stream ? stream->mailbox : "<no folder>" ));
  969. }
  970.  
  971.  
  972.  
  973. /*----------------------------------------------------------------------
  974.    Reset signals after critical imap code
  975.  ----*/
  976. void
  977. mm_nocritical(stream)
  978.      MAILSTREAM *stream;
  979.     stream = stream; /* For compiler complaints that this isn't used */
  980.  
  981. #if !defined(DOS) && !defined(OS2)
  982.     (void)signal(SIGHUP, hold_hup);
  983.     (void)signal(SIGUSR2, hold_usr2);
  984. #endif
  985.     (void)signal(SIGINT, hold_int);
  986.     (void)signal(SIGTERM, hold_term);
  987.     dprint(9, (debugfile, "Done with IMAP critical on %s\n",
  988.               stream ? stream->mailbox : "<no folder>" ));
  989. }
  990.